#region File Header

//----------------------------------------------------------------
// Copyright (C) 2002 Stefan Kyntchev
// All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT 
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR 
// FITNESS FOR A PARTICULAR PURPOSE.
//----------------------------------------------------------------

#endregion File Header

using System;
using System.Collections;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace AirWeb.WebControls.TreeControl
{
	/// <summary>
	///    Tree control class manages a tre-like structure of items. It is responsible to handle the interactions
	///    with the data model class as well as the expanding and collapsing of child branches. It delegates
	///    the drawing of the individual node items to a subclass of NodeItem.
	/// </summary>
	[DefaultProperty("Text"),
	 ToolboxData("<{0}:TreeControl runat=server></{0}:TreeControl>")]
	public class TreeControl : WebControl
	{
		protected int m_AutoExpandLevel;
		protected int m_BranchOffset;
		protected string m_CollapseIcon;
		protected string m_EmptyIcon;
		private Hashtable m_ExpandedNodes = new Hashtable();
		protected string m_ExpandIcon;
		protected string m_IfEmptyText = "There is nothing to display";
		private int m_LastChildID = 0;
		protected ITreeControlModel m_model = null;

		[Bindable(true), Category("Appearance"), DefaultValue("")] private TreeNode m_Root = null;

		protected int m_VertSpacing;

		#region Public Methods

		/// <summary>
		/// Tree control constructors 
		/// </summary>
		public TreeControl() : base()
		{
			InitControl();
		}

		public TreeControl(string i_tag) : base(i_tag)
		{
			InitControl();
		}

		/// <summary>
		/// Generates a unique node ID. Called by TreeNode constructor
		/// </summary>
		public int GenereteNodeID()
		{
			return ++m_LastChildID;
		}

		/// <summary>
		/// Reassign sequential node IDs to all children
		/// </summary>
		public void NormalizeChildIds()
		{
			m_LastChildID = -1;
			if (m_Root != null)
				m_Root.NormalizeChildIds();
		}

		/// <summary>
		/// Builds or (re-builds) the model for the tree control and renders it
		/// </summary>
		public void BuildControlContent()
		{
			//Recreate the tree data structure
			m_Root.DeleteAllChildren();
			m_LastChildID = 0;
			TreeModel.BuildModel(m_Root);

			//Render the tree controls
			if (m_Root.NodeCount > 0)
				m_Root.Render(Controls);
			else
			{
				Label l = new Label();
				l.Text = m_IfEmptyText;
				Controls.Add(l);
			}
		}

		/// <summary>
		/// Retrieves the stored state information for a particular node
		/// </summary>
		/// <param name="i_node">string node id that uniquely indentifies a particular node</param>
		/// <returns>integer value that represents the state</returns>
		public int GetNodeState(int i_node)
		{
			object t = m_ExpandedNodes[i_node];
			if (t != null)
			{
				return (int) t;
			}

			return -1;
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Tree model property sets the data model instance that will generate the data for this tree control
		/// </summary>
		public ITreeControlModel TreeModel
		{
			get { return m_model; }
			set { m_model = value; }
		}

		/// <summary>
		/// Returns the number of all children 
		/// </summary>
		public int NodeCount
		{
			get { return m_Root.NodeCount; }
		}

		/// <summary>
		/// Number of pixels child branches are indented relative to their parent
		/// </summary>
		public int BranchOffset
		{
			get { return m_BranchOffset; }
			set { m_BranchOffset = value; }
		}

		/// <summary>
		/// Number of pixels between tree items verticaly
		/// </summary>
		public int VertSpacing
		{
			get { return m_VertSpacing; }
			set { m_VertSpacing = value; }
		}

		/// <summary>
		/// Button image used to expand children
		/// </summary>
		public string ExpandIcon
		{
			get { return m_ExpandIcon; }
			set { m_ExpandIcon = value; }
		}

		/// <summary>
		/// Button image used to collapse children
		/// </summary>
		public string CollapseIcon
		{
			get { return m_CollapseIcon; }
			set { m_CollapseIcon = value; }
		}

		/// <summary>
		/// Empty transparent image used to be put in if no expand or collapse image is neccessary
		/// </summary>
		public string EmptyIcon
		{
			get { return m_EmptyIcon; }
			set { m_EmptyIcon = value; }
		}

		/// <summary>
		/// Set to a number. Show how many levels of children to be expanded.
		/// </summary>
		public int AutoExpandLevel
		{
			get
			{
				if (Page.IsPostBack)
					return 0;
				else
					return m_AutoExpandLevel;
			}
			set { m_AutoExpandLevel = Convert.ToInt16(value); }
		}

		/// <summary>
		/// Text that is displayed if the control does not have enything to display
		/// </summary>
		public string IfEmptyText
		{
			get { return m_IfEmptyText; }
			set { m_IfEmptyText = value; }
		}

		#endregion

		#region Protected Methods

		protected override object SaveViewState()
		{
			Hashtable state = new Hashtable();
			m_Root.GetControlState(state);
			return state;
		}


		protected override void LoadViewState(object savedState)
		{
			m_ExpandedNodes = (Hashtable) savedState;
		}


		/// <summary>
		/// As a response on this event the tree control renders it contents
		/// </summary>
		/// <param name="e"></param>
		protected override void OnLoad(EventArgs e)
		{
			if (TreeModel == null)
			{
				throw new ArgumentNullException("TreeModel", "Tree model was not set");
			}

			BuildControlContent();

			base.OnLoad(e);
		}


		protected void InitControl()
		{
			m_Root = new TreeNode(null);
			m_Root.MyTreeControl = this;
			m_Root.Expanded = true;

			// Set default settings for some attributes
			BranchOffset = 10; // pixels 
			VertSpacing = 4; // pixels
			m_AutoExpandLevel = 1; // expand only the root items
		}

		#endregion
	}
}